package asf.core
{
	import asf.sections.Section;
	
	public class ApplicationParser
	{
		private static const SECTIONS_NODE_NAME:String = "sections";
		private static const DEFAULT_NODE_NAME:String = "default";
		private static const APP_NODE_NAME:String = "app";
		
		public static function parse( raw:String, data:XML, app:* ):String
		{
			var initValue:XML = new XML( raw );
			
			var variables:Array
			var variable:String;
			
			var subVariables:Array;
			var subVariable:String;
			var subVariableNode:XML;
			
			var result:String = raw;
			
			if( result == null ) return "";
			
			if( initValue.children( ).length( ) >= 1 )
			{
				return getValue( initValue, data, app );
			}
			
			variables = getVariables( raw );
			
			for each( variable in variables )
			{
				if( variable.indexOf( "." ) == -1 )
				{
					result = result.replace( "{" + variable + "}", getValue( app.parameters[ variable ], data, app ) );
				}
				else
				{
					subVariables = variable.split( "." );
					
					var base:* = String( subVariables.shift( ) );
					var value:*;
					
					if( String( base ).toLowerCase( ) == SECTIONS_NODE_NAME )
					{
						var sectionID:String = String( subVariables.shift( ) );
						var sections:XMLList = ( app is Section )? ( app as Section ).application.getRawXML( ).sections.section: data.sections.section;
						
						for each( base in sections ) if( base.@id == sectionID || base.id == sectionID ) break;
					}
					else if( String( base ).toLowerCase( ) == APP_NODE_NAME )
					{
						if( app is Section )
						{
							//base = ( app as Section ).application.getRawXML( ).parameters;
							base = ( app as Section ).application.parameters;
						}
					}
					else
					{
						base = data[ base ];
					}
					
					value = base;
					
					for each( subVariable in subVariables )
					{
						value = value[ subVariable ];
					}
					
					result = result.replace( "{" + variable + "}", getValue( value, data, app ) );
				}
			}
			
			if( result.indexOf( "{" ) != -1 )
			{
				return parse( result, data, app );
			}
			else
			{
				return result;
			}
		}
		
		private static function getValue( node:*, data:XML, app:* ):String
		{
			if( node is String )
			{
				return parse( node, data, app );
			}
			else if( node is XML )
			{
				var nd:XML = node;
				var child:XML;
				
				if( nd.children( ).length( ) == 1 && nd.children( ).children( ).toString( ) == "" )
				{
					return parse( nd.children( ).toString( ), data, app );
				}
				
				for each( child in nd.children( ) )
				{
					if( child.name( ).toString( ).toLowerCase( ) != DEFAULT_NODE_NAME && child.attributes( ).length( ) > 0 )
					{
						var attrbs:XMLList = child.attributes( );
						var attrb:XML;
						var crit:Boolean = true;
						
						for each( attrb in attrbs )
						{
							switch( attrb.name( ).toString( ).toLowerCase( ) )
							{
								case "eq":
								{
									crit = crit && String( app.parameters[ child.name( ) ] ) == String( child.attribute( attrb.name( ) ) );
									break;
								}
								case "neq":
								{
									crit = crit && String( app.parameters[ child.name( ) ] ) != String( child.attribute( attrb.name( ) ) );
									break;
								}
								case "gt":
								{
									crit = crit && Number( app.parameters[ child.name( ) ] ) > Number( child.attribute( attrb.name( ) ) );
									break;
								}
								case "lt":
								{
									crit = crit && Number( app.parameters[ child.name( ) ] ) < Number( child.attribute( attrb.name( ) ) );
									break;
								}
								case "gte":
								{
									crit = crit && Number( app.parameters[ child.name( ) ] ) >= Number( child.attribute( attrb.name( ) ) );
									break;
								}
								case "lte":
								{
									crit = crit && Number( app.parameters[ child.name( ) ] ) <= Number( child.attribute( attrb.name( ) ) );
									break;
								}
							}
						}
						
						if( crit )
						{
							return getValue( child, data, app );
						}
					}
				}
				
				if( nd.hasOwnProperty( DEFAULT_NODE_NAME ) )
				{
					return getValue( nd[ DEFAULT_NODE_NAME ], data, app );
				}
			}
			
			return parse( String( node ), data, app );
		}
		
		private static function getVariables( value:String ):Array
		{
			var p1:int = -2;
			var p2:int = 0;
			var result:Array = new Array( );
			var tries:uint = 0;
			
			if( value == null ) return result;
			
			while( p1 != -1 && tries++ < 20 )
			{
				p1 = value.indexOf( "{", p1 + 1 );
				p2 = value.indexOf( "}", p1 );
				
				if( p1 != -1 && p2 != -1 ) result.push( value.substring( p1 + 1, p2 ) );
			}
			
			return result;
		}
	}
}